/*
 * This file is part of scheme-x-interface.
 *
 * scheme-x-interface is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * scheme-x-interface is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with scheme-x-interface.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * bridges a few of the gaps between C and Scheme
 */
#include <errno.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>

const int SCHEME_SOCK_STREAM = SOCK_STREAM;
const int SCHEME_SOCK_DGRAM = SOCK_DGRAM;

char* scheme_error;

int read_socket(int socket, char* bytevector, int start, int count)
{
  int numb = read(socket,bytevector+start,count);
  if(numb<0){
    printf("error %d:%s,%d\n",errno,__FILE__,__LINE__);
    //error
    return 0;
  }
  else{
    return numb;
  }
}

int write_socket(int socket, char* bytevector, int start, int count)
{
  if(count==0){
    return close(socket);
  }
  int numb = write(socket,bytevector+start,count);
  if(numb<0){
    printf("error %d:%s,%d\n",errno,__FILE__,__LINE__);
    //error
    return 0;
  }
  return numb;
}

int get_unix_socket(int type,int abstract,const char* path)
{
  struct sockaddr_un addr;
  int size = make_unix_sockaddr(abstract,path,&addr);
  if(!size){
    //error
    printf("error %d:%s,%d\n",errno,__FILE__,__LINE__);
    return -1;
  }
  int sock = socket(PF_UNIX,type,0);
  if(sock<0){
    //error
    printf("error %d:%s,%d\n",errno,__FILE__,__LINE__);
    return -1;
  }
  if(connect(sock,&addr,size)){
    //error
    
    printf("error %d:%s,%d\n",errno,__FILE__,__LINE__);
    return -1;
  }
  return sock;
}

//string is a null terminated string
//returned value is the size
int make_unix_sockaddr(int abstract,const char* string,struct sockaddr_un* addr)
{
  size_t max_path_length = 
    sizeof(struct sockaddr_un)-offsetof(struct sockaddr_un,sun_path)-1;
  if(abstract){
    max_path_length--;
  }
  if(strlen(string)>max_path_length){
    //error
    printf("error %d:%s,%d\n",errno,__FILE__,__LINE__);
    return 0;
  }
  addr->sun_family = AF_UNIX;
  if(abstract){
    strcpy(addr->sun_path+1,string);
    addr->sun_path[0]='\0';
  }
  else{
    strcpy(addr->sun_path,string);
  }
  return offsetof(struct sockaddr_un, sun_path) + strlen(string) 
	  + (abstract ? 2 : 1);
}
